﻿#pragma once

#include "websocket.hh"

#include "../../box/box_network.hh"
#include "../box_std_allocator.hh"
#include "../object_pool.hh"

#include <unordered_map>

namespace kratos {
namespace service {
class ServiceBox;
}
} // namespace kratos

struct http_parser_settings;
struct http_parser;
struct BoxChannelUserData;

namespace kratos {
namespace ws {

class WebSocketChannelImpl;

using BoxChannelPtr = std::shared_ptr<kratos::service::BoxChannel>;
using ServiceBoxPointer = kratos::service::ServiceBox *;
using WebSocketChannelMap =
    kratos::service::PoolUnorederedMap<std::uint64_t, WebSocketChannelPtr>;

/**
 * @brief 接收帧返回状态
 */
enum class FrameStatus {
  CONT,   ///< 继续接收后续帧
  EXIT,   ///< 不完整帧，或非数据帧
  PACKET, ///< 接收到一个完整数据包
};

/**
 * @brief 操作码，占用4个bit位
 */
struct OPCODE {
  constexpr static int SLICE_FRAME =
      0x0; ///< 当前数据帧为分片的数据帧，也就是当一个消息需要分成多个数据帧来传送的时候，需要将opcode设置位0x0
  constexpr static int TEXT_FRAME = 0x1; ///< 当前数据帧传递的内容是文本
  constexpr static int BINARY_FRAME =
      0x2; ///< 当前数据帧传递的是二进制内容，不要转换成字符串
  constexpr static int CLOSE = 0x3; ///< 请求关闭连接
  constexpr static int PING = 0x9;  ///< Ping请求
  constexpr static int PONG =
      0xa; ///< Pong数据包，当收到Ping请求时自动给回一个Pong
};

constexpr static std::size_t BUFFER_LENGTH = 1024 * 1024; ///< 缓冲区长度
constexpr static int RINGBUFFER_INIT_LENGTH = 16 * 1024; ///< 暂存缓冲区长度
constexpr static int LENGTH_GAP = 125;                   ///< 小帧长度上限
constexpr static int EXTEND_GAP = 65535;       ///< 中等扩展帧长度上限
constexpr static int BIT_16_LENGTH_FLAG = 126; ///< 中等帧Payload len长度标识
constexpr static int BIT_64_LENGTH_FLAG = 127; ///< 长帧Payload len长度标识
constexpr static int LENGTH_BYTE = 2; ///< Payload len字段字节数(包含mask)
constexpr static int EXTEND_BYTE = 8; ///< Extended payload length字段字节数
constexpr static int HEADER_BASIC_BYTE = 2; ///< 协议头最小字节数
constexpr static int HEADER_LENGTH_BYTE =
    4; ///< 协议头包含Payload len字段字节数
constexpr static int HEADER_EXTEND_LENGTH_BYTE =
    10; ///< 协议头包含Extended payload length字段字节数
constexpr static int HEADER_MASK_BYTE = 14; ///< 协议头包含Mask key字段字节数
constexpr static int MASK_BYTE = 4;         ///< Mask key 字节数

/**
 * @brief Websocket服务器
 */
class WebSocketServerImpl : public WebSocketServer,
                            public kratos::service::BoxNetwork {
  ServiceBoxPointer box_{nullptr};            ///< 服务容器
  kratos::unique_pool_ptr<char> buffer_;      ///< 缓冲区
  WebSocketChannelMap websocket_channel_map_; ///< 管道管理
  WebSocketCallback callback_;                ///< 用户事件回调

public:
  /**
   * @brief 构造
   * @param box 服务容器
   */
  WebSocketServerImpl(ServiceBoxPointer box);
  /**
   * @brief 析构
   */
  virtual ~WebSocketServerImpl();
  virtual auto startup(WebSocketCallback callback) -> bool override;
  virtual auto shutdown() -> bool override;

public:
  /**
   * 获取服务容器配置
   *
   * \return 服务容器配置
   */
  virtual auto get_config() -> kratos::config::BoxConfig & override;
  /**
   * 获取日志添加器.
   *
   * \return
   */
  virtual auto get_logger_appender() -> klogger::Appender * override;

  /**
   * 获取本地化实例.
   *
   * \return 本地化实例
   */
  virtual auto get_lang() -> lang::Lang * override;
  /**
   * 开启监听事件
   *
   * \param name 监听器名称
   * \param success 成功或失败
   * \param channel 监听管道
   */
  virtual void on_listen(const std::string &name, bool success,
                         BoxChannelPtr &channel) override;
  /**
   * 接受一个新的连接建立
   *
   * \param channel 新建立的管道
   */
  virtual void on_accept(BoxChannelPtr &channel) override;
  /**
   * 连接到一个远程监听器
   *
   * \param name 连接器名称
   * \param success 成功或失败
   * \param channel 新建立的管道
   */
  virtual void on_connect(const std::string &name, bool success,
                          BoxChannelPtr &channel) override;
  /**
   * 关闭管道事件
   *
   * \param channel 关闭的管道
   */
  virtual void on_close(BoxChannelPtr &channel) override;
  /**
   * 数据事件
   *
   * \param channel 接收到数据的管道
   */
  virtual void on_data(BoxChannelPtr &channel) override;
  /**
   * @brief 获取WebSocket管道
   * @param channel_id 管道ID
   * @return WebSocket管道
  */
  virtual auto get_channel(std::uint64_t channel_id)->WebSocketChannelPtr override;

private:
  /**
   * @brief 返回握手信息，协议升级完成
   * @param channel 客户端管道
   * @param user_data 用户数据
   * @return
   */
  auto return_handshake(BoxChannelPtr &channel, BoxChannelUserData *user_data)
      -> void;
  /**
   * @brief 发送pong
   * @param channel
   * @return
   */
  auto return_pong(BoxChannelPtr &channel);
  /**
   * @brief 向客户端发送数据
   * @param channel 客户端管道
   * @param data 数据指针
   * @param size 数据长度
   * @param is_binary 是否是二进制协议，false则为文本协议
   * @return
   */
  auto send(BoxChannelPtr &channel, const char *data, int size, bool is_binary)
      -> int;
  /**
   * @brief 从客户端管道内读取数据帧
   * @param channel 客户端管道
   * @param user_data 用户数据
   * @return FrameStatus
   */
  auto try_get_data(BoxChannelPtr &channel, BoxChannelUserData *user_data)
      -> FrameStatus;
  /**
   * @brief 设置HTTP解析器回调设置
   * @param settings 回调设置
   * @return
   */
  auto setup_http_parser_settings(http_parser_settings *settings) -> void;
  /**
   * @brief 调用用户回调
   * @param e 事件
   * @param channel 管道
   * @return
   */
  auto call_cb(WebSocketEvent e, WebSocketChannelPtr channel) -> void;
  /**
   * @brief 获取与BoxChannel相关联的WebSocketChannel
   * @param box_channel 容器管道
   * @return WebSocketChannel
   */
  auto from_box_channel(BoxChannelPtr box_channel) -> WebSocketChannelPtr;

private:
  /**
   * @brief 填充数据帧类型
   * @param [IN OUT]buffer 缓冲区
   * @param [IN OUT]pos 当前位置
   * @param type 帧类型
   * @return
   */
  auto fill_data_frame_type(char *buffer, int &pos, std::uint8_t type) -> void;
  /**
   * @brief 填充帧Payload长度
   * @param [IN OUT]buffer 缓冲区
   * @param [IN OUT]pos 当前位置
   * @param size Payload长度
   * @return
   */
  auto fill_frame_header_length(char *buffer, int &pos, int size) -> void;
  /**
   * @brief 获取opcode
   * @param byte 字节
   * @return opcode
   */
  auto get_opcode(char byte) -> int;
  /**
   * @brief 获取fin
   * @param byte 字节
   * @return true或false
   */
  auto get_fin(char byte) -> bool;
  /**
   * @brief 获取mask
   * @param byte 字节
   * @return true或false
   */
  auto get_mask(char byte) -> bool;
  /**
   * @brief 获取Payload len
   * @param byte 字节
   * @return Payload len
   */
  auto get_basic_length(char byte) -> int;
  /**
   * @brief 获取Extended payload length(2字节)
   * @param buffer 缓冲区地址
   * @return Extended payload length
   */
  auto get_extend_length_basic(char *buffer) -> int;
  /**
   * @brief 获取Extended payload length(8字节)
   * @param buffer 缓冲区地址
   * @return Extended payload length
   */
  auto get_extend_length(char *buffer) -> std::uint64_t;
  /**
   * @brief 获取masking-key(4字节)
   * @param buffer 缓冲区地址
   * @return masking-key
   */
  auto get_mask_key(char *buffer) -> std::uint32_t;
  /**
   * @brief 解密掩码
   * @param mask_key 掩码
   * @param buffer 缓冲区地址
   * @param length 数据长度
   * @return
   */
  auto unmask_payload(std::uint32_t mask_key, char *buffer,
                      std::uint64_t length) -> void;
  /**
   * @brief 解析协议头
   * @param channel 数据来源管道
   * @param fin fin
   * @param opcode opcode
   * @param payload_pos payload起始偏移字节
   * @param length payload长度
   * @param mask_key masking-key
   * @return true或false
   */
  auto parse_header(BoxChannelPtr &channel, bool &fin, int &opcode,
                    std::size_t &payload_pos, std::uint64_t &length,
                    std::uint32_t &mask_key) -> bool;
  /**
   * @brief 接收payload
   * @param channel 数据来源管道
   * @param user_data 管道自定义用户数据
   * @param fin fin
   * @param opcode opcode
   * @param length payload长度
   * @return 帧状态
   */
  auto parser_header_after_phase(BoxChannelPtr &channel,
                                 BoxChannelUserData *user_data, bool fin,
                                 int opcode, std::uint64_t length)
      -> FrameStatus;

private:
  //// 以下函数为http_parser_settings的回调函数，具体含义参见@see http_parser

  static int on_message_begin(http_parser *);
  static int on_message_complete(http_parser *);
  static int on_url(http_parser *, const char *at, std::size_t length);
  static int on_header_field(http_parser *, const char *at, std::size_t length);
  static int on_header_value(http_parser *, const char *at, std::size_t length);
  static int on_status(http_parser *, const char *at, std::size_t length);
  static int on_headers_complete(http_parser *);
  static int on_body(http_parser *, const char *at, std::size_t length);
  static int on_chunk_header(http_parser *);
  static int on_chunk_complete(http_parser *);

  friend class WebSocketChannelImpl;
};
/**
 * @brief WebSocket管道, 提供一层对用户友好的包装
 */
class WebSocketChannelImpl : public WebSocketChannel {
  BoxChannelUserData *user_data_{nullptr}; ///< 用户数据，不控制声明周期
  kratos::unique_pool_ptr<char> buffer_; ///< 缓冲区
  int buffer_size_{0};                   ///< 缓冲区长度
  std::uint64_t id_{0};                  ///< 管道ID

public:
  /**
   * @brief 构造
   * @param user_data 用户数据
   */
  WebSocketChannelImpl(BoxChannelUserData *user_data);
  /**
   * @brief 析构
   */
  virtual ~WebSocketChannelImpl();
  virtual int send(const char *data, const int size) override;
  virtual int peek(char *data, const int size) override;
  virtual int recv(char *data, const int size) override;
  virtual int skip(const int size) override;
  virtual int size() override;
  virtual bool isClose() override;
  virtual void close() override;

  virtual auto send(const std::string &data) -> int override;
  virtual auto recv(std::string &str) -> int override;
  virtual auto get_id() -> std::uint64_t override;

public:
  auto set_id(std::uint64_t id) -> void;
};

} // namespace ws
} // namespace kratos
